package com.example.smartwaterapi.controller;

import com.example.smartwaterapi.common.api.RestApiResponse;
import com.example.smartwaterapi.service.UserService;
import com.example.smartwaterapi.service.WechatService;
import com.example.smartwaterapi.entity.User;
import com.example.smartwaterapi.config.WechatConfig;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信公众号绑定控制器
 */
@Slf4j
@Tag(name = "微信公众号绑定", description = "微信公众号openid绑定相关接口")
@RestController
@RequestMapping("/api/wechat")
public class WechatBindController {

    @Autowired
    private UserService userService;
    
    @Autowired
    private WechatService wechatService;
    
    @Autowired
    private WechatConfig wechatConfig;
    
    @Autowired
    private RestTemplate restTemplate;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    @Value("${app.domain:https://xhd.szxhdkj.com}")
    private String appDomain;

    /**
     * 绑定微信公众号openid
     * 
     * 当用户从公众号进入小程序时，自动获取并绑定公众号的openid
     * 这样就可以向用户发送模板消息了
     */
    @Operation(summary = "绑定微信公众号openid", description = "用户从公众号进入小程序时绑定openid以接收模板消息")
    @PostMapping("/bind-openid")
    public RestApiResponse<Boolean> bindWechatOpenid(@RequestBody Map<String, Object> requestData) {
        
        try {
            // 获取参数
            Long userId = Long.valueOf(requestData.get("userId").toString());
            Integer scene = requestData.get("scene") != null ? 
                Integer.valueOf(requestData.get("scene").toString()) : null;
            String referrerAppId = (String) requestData.get("referrerAppId");
            String authCode = (String) requestData.get("authCode"); // 新增：公众号授权码
            
            log.info("绑定微信公众号openid请求: userId={}, scene={}, referrerAppId={}, authCode={}", 
                userId, scene, referrerAppId, authCode != null ? "已提供" : "未提供");
            
            // 检查用户是否存在
            User user = userService.getById(userId);
            if (user == null) {
                return RestApiResponse.businessError("50001", "用户不存在");
            }
            
            // 验证是否来自公众号（场景值校验）
            if (!isFromOfficialAccount(scene)) {
                log.warn("公众号绑定失败: 无效的场景值 - scene={}, 有效场景值: [1035, 1043, 1014, 1058, 1082]", scene);
                return RestApiResponse.businessError("50004", "请从微信公众号进入小程序后再进行绑定，当前场景值: " + scene);
            }
            
            log.info("场景值验证通过: scene={} 确认来自公众号", scene);
            
            // 检查是否已经绑定
            if (user.getWxOpenid() != null && !user.getWxOpenid().isEmpty()) {
                log.info("用户已绑定微信公众号: userId={}, openid={}", userId, 
                    user.getWxOpenid().substring(0, Math.min(8, user.getWxOpenid().length())) + "***");
                return RestApiResponse.ok("用户已绑定微信公众号", true);
            }
            
            // 真实获取公众号openid
            String realOpenid = null;
            
            if (StringUtils.hasText(authCode)) {
                // 检查是否直接传入了公众号openid（从网页授权跳转过来）
                if (authCode.startsWith("o") && authCode.length() > 20) {
                    log.info("🎯 检测到直接传入的公众号openid: {}", authCode.substring(0, 10) + "...");
                    realOpenid = authCode;
                } else {
                    // 传统方式：通过授权码获取openid
                    log.info("🔑 通过授权码获取公众号openid");
                    realOpenid = getOfficialAccountOpenidByCode(authCode);
                }
            } else {
                // 如果没有授权码，尝试通过unionid获取
                log.info("尝试通过unionid获取公众号openid");
                if (StringUtils.hasText(user.getUnionid())) {
                    realOpenid = getOfficialAccountOpenidByUnionid(user.getUnionid());
                }
            }
            
            // 如果仍然无法获取公众号openid
            if (!StringUtils.hasText(realOpenid)) {
                log.warn("❌ 无法获取公众号openid - authCode={}, unionid={}", 
                    authCode != null ? "已提供" : "未提供", 
                    StringUtils.hasText(user.getUnionid()) ? "已提供" : "未提供");
                
                log.info("💡 获取公众号openid的正确方式:");
                log.info("   1. 用户从公众号菜单进入时，应该先进行网页授权");
                log.info("   2. 网页授权会返回authCode，通过authCode可以获取公众号openid");
                log.info("   3. 或者确保小程序和公众号在同一个开放平台下，通过unionid关联");
                
                // ⚠️ 重要提示：建议引导用户进行网页授权
                log.warn("🔔 建议处理方案:");
                log.warn("   1. 返回特定错误码，提示用户需要网页授权");
                log.warn("   2. 小程序引导用户访问授权URL: {}/wechat/auth/authorize", appDomain);
                log.warn("   3. 用户完成授权后会自动跳转回小程序并携带openid");
                
                // 在生产环境中，应该返回错误而不是使用模拟数据
                if (isProductionEnvironment()) {
                    return RestApiResponse.businessError("50005", 
                        "无法获取公众号openid，请从公众号进入小程序或点击授权链接: " + appDomain + "/wechat/auth/authorize?state=miniprogram_bind");
                }
                
                // 仅在测试环境使用模拟openid
                log.warn("⚠️ 测试环境：使用模拟openid");
                realOpenid = generateMockOpenid(userId, referrerAppId);
            }
            
            // 更新用户的微信openid
            User updateUser = new User();
            updateUser.setId(userId);
            updateUser.setWxOpenid(realOpenid);
            updateUser.setUpdatedAt(LocalDateTime.now());
            
            boolean result = userService.updateById(updateUser);
            
            if (result) {
                log.info("微信公众号绑定成功: userId={}, openid={}", userId, 
                    realOpenid.substring(0, Math.min(8, realOpenid.length())) + "***");
                return RestApiResponse.ok("微信公众号绑定成功", true);
            } else {
                return RestApiResponse.businessError("50002", "绑定失败");
            }
            
        } catch (Exception e) {
            log.error("绑定微信公众号openid异常", e);
            return RestApiResponse.businessError("50002", "绑定失败: " + e.getMessage());
        }
    }

    /**
     * 通过授权码获取公众号openid
     */
    private String getOfficialAccountOpenidByCode(String code) {
        try {
            log.info("🔑 通过授权码获取公众号openid: code={}", code);
            
            // 调用WechatService的方法获取用户信息
            var userInfo = wechatService.getOfficialAccountUserInfo(code);
            if (userInfo != null && StringUtils.hasText(userInfo.getOpenid())) {
                log.info("✅ 成功获取公众号openid: {}", userInfo.getOpenid().substring(0, 10) + "...");
                return userInfo.getOpenid();
            } else {
                                 log.error("❌ 获取公众号用户信息失败");
                 return null;
             }
             
        } catch (Exception e) {
            log.error("❌ 获取公众号openid异常", e);
            return null;
        }
    }
    
    /**
     * 通过unionid获取公众号openid
     * 注意：微信API没有直接通过unionid获取openid的接口
     * 这里采用数据库查询的方式（如果之前有过公众号授权记录）
     */
    private String getOfficialAccountOpenidByUnionid(String unionid) {
        try {
            log.info("尝试通过unionid获取公众号openid: unionid={}", unionid);
            
            // ⚠️ 重要说明：微信API没有直接通过unionid获取公众号openid的接口
            // 正确的做法是：
            // 1. 用户需要先进行公众号网页授权，获取到公众号openid和unionid的对应关系
            // 2. 将这个对应关系保存到数据库
            // 3. 后续可以通过数据库查询获取
            
            // 这里暂时返回null，表示无法获取
            // 实际项目中应该查询数据库中是否有该unionid对应的公众号openid记录
            
            log.warn("⚠️ 通过unionid获取公众号openid失败: 微信API不支持此操作，需要先进行公众号网页授权");
            log.info("💡 建议：引导用户进行公众号网页授权以获取openid");
            
            return null;
            
        } catch (Exception e) {
            log.error("通过unionid获取公众号openid异常", e);
            return null;
        }
    }
    
    /**
     * 获取公众号access_token
     */
    private String getOfficialAccountAccessToken() {
        try {
            String url = String.format(
                "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
                wechatConfig.getAppid(), wechatConfig.getAppSecret()
            );
            
            String response = restTemplate.getForObject(url, String.class);
            Map<String, Object> result = objectMapper.readValue(response, Map.class);
            
            if (result.containsKey("access_token")) {
                return (String) result.get("access_token");
            } else {
                log.error("获取公众号access_token失败: {}", result);
                return null;
            }
        } catch (Exception e) {
            log.error("获取公众号access_token异常", e);
            return null;
        }
    }

    /**
     * 检查用户微信公众号绑定状态
     */
    @Operation(summary = "检查微信绑定状态", description = "检查用户是否已绑定微信公众号")
    @GetMapping("/binding/{userId}")
    public RestApiResponse<Map<String, Object>> checkWechatBinding(
            @Parameter(description = "用户ID", required = true) @PathVariable Long userId) {
        
        try {
            User user = userService.getById(userId);
            if (user == null) {
                return RestApiResponse.businessError("50001", "用户不存在");
            }
            
            Map<String, Object> bindingInfo = new HashMap<>();
            boolean isWxBound = user.getWxOpenid() != null && !user.getWxOpenid().isEmpty();
            
            bindingInfo.put("isWxBound", isWxBound);
            bindingInfo.put("reminderEnabled", user.getReminderEnabled() == 1);
            
            if (isWxBound) {
                // 只显示openid的前几位，保护隐私
                String maskedOpenid = user.getWxOpenid().substring(0, Math.min(8, user.getWxOpenid().length())) + "***";
                bindingInfo.put("maskedOpenid", maskedOpenid);
            }
            
            return RestApiResponse.ok("获取绑定状态成功", bindingInfo);
            
        } catch (Exception e) {
            log.error("检查微信绑定状态异常: userId={}", userId, e);
            return RestApiResponse.businessError("50002", "获取绑定状态失败: " + e.getMessage());
        }
    }
    
    /**
     * 验证场景值是否来自公众号
     */
    private boolean isFromOfficialAccount(Integer scene) {
        if (scene == null) {
            return false;
        }
        
        // 微信小程序场景值参考：https://developers.weixin.qq.com/miniprogram/dev/reference/scene-list.html
        // 来自公众号的场景值
        int[] officialAccountScenes = {
            1035, // 公众号自定义菜单
            1043, // 公众号模板消息
            1014, // 公众号profile页
            1058, // 公众号文章
            1082, // 长按图片识别小程序码
        };
        
        for (int validScene : officialAccountScenes) {
            if (scene == validScene) {
                return true;
            }
        }
        
        log.warn("无效的公众号场景值: {}", scene);
        return false;
    }
    
    /**
     * 检查是否为生产环境
     */
    private boolean isProductionEnvironment() {
        // 这里可以根据实际情况判断环境
        // 例如检查环境变量、配置文件等
        String env = System.getProperty("spring.profiles.active", "dev");
        return "prod".equals(env) || "production".equals(env);
    }
    
    /**
     * 生成模拟的openid（生产环境应通过微信API获取真实openid）
     */
    private String generateMockOpenid(Long userId, String referrerAppId) {
        // 这里是模拟生成，实际应该通过微信API获取
        // 格式：o + AppID后6位 + 用户ID + 时间戳后6位
        String appIdSuffix = referrerAppId != null && referrerAppId.length() >= 6 ? 
            referrerAppId.substring(referrerAppId.length() - 6) : "wx54ab";
        
        String timestamp = String.valueOf(System.currentTimeMillis());
        String timestampSuffix = timestamp.substring(timestamp.length() - 6);
        
        return "o" + appIdSuffix + String.format("%06d", userId) + timestampSuffix;
    }
} 